package com.onenine.app.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;

import com.onenine.common.util.Logger;

import org.greenrobot.eventbus.EventBus;

import java.io.Serializable;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 阻塞式消息队列任务服务
 *
 * @author fly
 */
public class MessageQueueService<T> extends Service {

    public static final String ACTION_TASK_BEGIN = "com.onenine.app.action.TASK_START";
    public static final String ACTION_TASK_END = "com.onenine.app.action.TASK_END";
    private TaskQueue mTaskQueue;
    private TakeThread mTakeThread;
    private final Object mLockObj = new Object();

    /**
     * 开始一个任务
     *
     * @param context
     * @param message
     */
    public static <T> void beginMessageService(Context context, T message) {
        Intent intent = new Intent(context, MessageQueueService.class);
        intent.setAction(ACTION_TASK_BEGIN);
        intent.setPackage(context.getPackageName());
        intent.putExtra("data", (Serializable) message);
        context.startService(intent);
    }

    /**
     * 结束一个消息任务
     *
     * @param context
     */
    public static void endMessageService(Context context) {
        Intent intent = new Intent(context, MessageQueueService.class);
        intent.setAction(ACTION_TASK_END);
        intent.setPackage(context.getPackageName());
        context.startService(intent);
    }

    /**
     * 停止服务
     *
     * @param context
     */
    public static void stopMessageService(Context context) {
        Intent intent = new Intent(context, MessageQueueService.class);
        intent.setPackage(context.getPackageName());
        context.stopService(intent);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mTaskQueue = new TaskQueue();
        mTakeThread = new TakeThread(mTaskQueue, mLockObj);
        mTakeThread.start();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            if (ACTION_TASK_BEGIN.equals(intent.getAction())) {
                //创建任务
                createTask(intent);
            } else if (ACTION_TASK_END.equals(intent.getAction())) {
                //完成任务
                finishTask();
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mTakeThread.setLoop(false);
    }

    /**
     * 创建任务
     */
    private void createTask(Intent intent) {
        T message = (T) intent.getSerializableExtra("data");
        if (message != null) {
            Logger.e("收到任务：" + message);
            PutThread putThread = new PutThread(mTaskQueue, message);
            putThread.start();
        }
    }

    /**
     * 完成任务
     */
    private void finishTask() {
        //本线程开始持有lockObj对象锁
        synchronized (mLockObj) {
            //任务已完成，调用完notify()方法后会释放lockObj对象锁，并唤醒lockObj所在等待的线程
            mLockObj.notify();
            Logger.e("任务已完成，开始唤醒等待的线程");
        }
    }

    /**
     * 定义保存任务的FIFO阻塞队列
     */
    public class TaskQueue<T> {
        /**
         * 队列，能够容纳Integer.MAX_VALUE个任务
         */
        private BlockingQueue<T> tasks = new LinkedBlockingQueue<>();

        /**
         * 生产任务，加入队列
         */
        public void put(T task) throws InterruptedException {
            // put方法放入一个任务，若tasks满了，等到tasks有空间为止(加入到最后一个位置)
            tasks.put(task);
        }

        /**
         * 消费任务，从队列中取出
         */
        public T take() throws InterruptedException {
            // take方法取出一个任务，若tasks为空，等到tasks有任务为止(获取并移除此队列的头部)
            return tasks.take();
        }
    }

    /**
     * 定义任务生产者
     */
    private class PutThread extends Thread {
        private TaskQueue taskQueue;
        private T messageTask;

        public PutThread(TaskQueue taskQueue, T task) {
            this.taskQueue = taskQueue;
            this.messageTask = task;
        }

        @Override
        public void run() {
            try {
                //生产任务
                Logger.e("开始把任务加入队列中");
                taskQueue.put(messageTask);
                Logger.e("任务已成功被加入队列");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 定义任务消费者
     */
    private class TakeThread extends Thread {
        private TaskQueue taskQueue;
        private final Object lockObj;
        private boolean isLoop;

        public void setLoop(boolean loop) {
            isLoop = loop;
        }

        public TakeThread(TaskQueue taskQueue, Object lockObj) {
            this.taskQueue = taskQueue;
            this.lockObj = lockObj;
            isLoop = true;
        }

        @Override
        public void run() {
            try {
                while (isLoop) {
                    //消费任务
                    T messageTask = (T) taskQueue.take();
                    Logger.e("任务已取出，开始处理并分发任务");
                    EventBus.getDefault().post(messageTask);
                    //本线程开始持有lockObj对象锁
                    synchronized (lockObj) {
                        Logger.e("任务未完成，开始进入等待模式");
                        //任务未完成，调用完wait()方法后会释放lockObj对象锁，本线程开始进入等待模式，后面代码将不会执行
                        lockObj.wait();
                        Logger.e("等待结束，开始下一个任务");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}